using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using RaisingStudio.SmallProgram.Library;
using RaisingStudio.SmallBasicCompiler.Statements;

namespace RaisingStudio.SmallBasicCompiler.Completion
{
    public class CompletionHelper
    {
        private Compiler _compiler;
        public CompletionHelper()
        {
            this._compiler = new Compiler();
        }
        public CompletionBag GetEmptyCompletionBag()
        {
            return new CompletionBag(this._compiler.TypeInfoBag, this._compiler.Parser.SymbolTable);
        }
        public CompletionBag GetCompletionItems(TextReader source, int line, int column)
        {
            this._compiler.Compile(source);
            CompletionBag emptyCompletionBag = this.GetEmptyCompletionBag();
            Statement statement = null;
            for (int i = this._compiler.Parser.ParseTree.Count - 1; i >= 0; i--)
            {
                Statement statement2 = this._compiler.Parser.ParseTree[i];
                if (line >= statement2.StartToken.Line)
                {
                    statement = statement2;
                    break;
                }
            }
            if (statement != null)
            {
                this.FillCompletionItemsFromStatement(statement, emptyCompletionBag, line, column);
            }
            else
            {
                CompletionHelper.FillAllGlobalItems(emptyCompletionBag, true);
            }
            emptyCompletionBag.CompletionItems.Sort((CompletionItem ci1, CompletionItem ci2) => ci1.DisplayName.CompareTo(ci2.DisplayName));
            return emptyCompletionBag;
        }
        public int GetIndentationLevel(TextReader source, int lineNumber)
        {
            this._compiler.Compile(source);
            return this.GetIndentationLevel(lineNumber);
        }
        public int GetIndentationLevel(int lineNumber)
        {
            Statement statementContaining = Statement.GetStatementContaining(this._compiler.Parser.ParseTree, lineNumber);
            if (statementContaining != null)
            {
                return statementContaining.GetIndentationLevel(lineNumber);
            }
            return 0;
        }
        private void FillCompletionItemsFromStatement(Statement statement, CompletionBag completionBag, int line, int column)
        {
            statement.PopulateCompletionItems(completionBag, line, column, true);
        }
        public static void FillAllGlobalItems(CompletionBag completionBag, bool inGlobalScope)
        {
            CompletionHelper.FillExpressionItems(completionBag);
            CompletionHelper.FillAllKeywords(completionBag);
            CompletionHelper.FillSubroutines(completionBag);
            if (inGlobalScope)
            {
                CompletionHelper.FillKeywords(completionBag, new Token[]
				{
					Token.Sub
				});
            }
        }
        public static void FillAllKeywords(CompletionBag completionBag)
        {
            CompletionHelper.FillKeywords(completionBag, new Token[]
			{
				Token.If, 
				Token.For, 
				Token.Goto, 
				Token.While
			});
        }
        public static void FillLogicalExpressionItems(CompletionBag completionBag)
        {
            CompletionHelper.FillExpressionItems(completionBag);
            CompletionHelper.FillKeywords(completionBag, new Token[]
			{
				Token.And, 
				Token.Or
			});
        }
        public static void FillExpressionItems(CompletionBag completionBag)
        {
            CompletionHelper.FillTypeNames(completionBag);
            CompletionHelper.FillVariables(completionBag);
        }
        public static void FillSubroutines(CompletionBag completionBag)
        {
            foreach (KeyValuePair<string, TokenInfo> current in completionBag.SymbolTable.Subroutines)
            {
                CompletionItem item = new CompletionItem
                {
                    Name = current.Key,
                    DisplayName = current.Value.Text,
                    ReplacementText = current.Value.Text + "()",
                    ItemType = CompletionItemType.SubroutineName
                };
                completionBag.CompletionItems.Add(item);
            }
        }
        public static void FillLabels(CompletionBag completionBag)
        {
            foreach (KeyValuePair<string, TokenInfo> current in completionBag.SymbolTable.Labels)
            {
                CompletionItem item = new CompletionItem
                {
                    Name = current.Key,
                    DisplayName = current.Value.Text,
                    ItemType = CompletionItemType.Label
                };
                completionBag.CompletionItems.Add(item);
            }
        }
        public static void FillVariables(CompletionBag completionBag)
        {
            foreach (KeyValuePair<string, TokenInfo> current in completionBag.SymbolTable.Variables)
            {
                CompletionItem item = new CompletionItem
                {
                    Name = current.Key,
                    DisplayName = current.Value.Text,
                    ItemType = CompletionItemType.Variable
                };
                completionBag.CompletionItems.Add(item);
            }
        }
        public static void FillTypeNames(CompletionBag completionBag)
        {
            foreach (KeyValuePair<string, TypeInfo> current in completionBag.TypeInfoBag.Types)
            {
                if (!current.Value.HideFromIntellisense)
                {
                    CompletionItem item = new CompletionItem
                    {
                        Name = current.Key,
                        DisplayName = current.Value.Type.Name,
                        ItemType = CompletionItemType.TypeName,
                        MemberInfo = current.Value.Type
                    };
                    completionBag.CompletionItems.Add(item);
                }
            }
        }
        public static void FillMemberNames(CompletionBag completionBag, TypeInfo typeInfo)
        {
            foreach (KeyValuePair<string, MethodInfo> current in typeInfo.Methods)
            {
                if (!CompletionHelper.IsHiddenFromIntellisense(current.Value))
                {
                    CompletionItem completionItem = new CompletionItem
                    {
                        Name = current.Key,
                        DisplayName = current.Value.Name,
                        ItemType = CompletionItemType.MethodName,
                        MemberInfo = current.Value
                    };
                    if (current.Value.GetParameters().Length == 0)
                    {
                        completionItem.ReplacementText = current.Value.Name + "()";
                    }
                    completionBag.CompletionItems.Add(completionItem);
                }
            }
            foreach (KeyValuePair<string, PropertyInfo> current2 in typeInfo.Properties)
            {
                if (!CompletionHelper.IsHiddenFromIntellisense(current2.Value))
                {
                    CompletionItem item = new CompletionItem
                    {
                        Name = current2.Key,
                        DisplayName = current2.Value.Name,
                        ItemType = CompletionItemType.PropertyName,
                        MemberInfo = current2.Value
                    };
                    completionBag.CompletionItems.Add(item);
                }
            }
            foreach (KeyValuePair<string, EventInfo> current3 in typeInfo.Events)
            {
                if (!CompletionHelper.IsHiddenFromIntellisense(current3.Value))
                {
                    CompletionItem item2 = new CompletionItem
                    {
                        Name = current3.Key,
                        DisplayName = current3.Value.Name,
                        ItemType = CompletionItemType.EventName,
                        MemberInfo = current3.Value
                    };
                    completionBag.CompletionItems.Add(item2);
                }
            }
        }
        public static void FillKeywords(CompletionBag completionBag, params Token[] keywords)
        {
            for (int i = 0; i < keywords.Length; i++)
            {
                Token token = keywords[i];
                CompletionItem item = new CompletionItem
                {
                    Name = token.ToString(),
                    DisplayName = token.ToString(),
                    ItemType = CompletionItemType.Keyword
                };
                completionBag.CompletionItems.Add(item);
            }
        }
        private static bool IsHiddenFromIntellisense(MemberInfo mi)
        {
            return mi.GetCustomAttributes(typeof(HideFromIntellisenseAttribute), false).Length > 0;
        }
    }
}